package com.atguigu.tingshu.user.service.impl;

import com.alibaba.fastjson.JSONObject;
import com.atguigu.tingshu.common.rabbit.constant.MqConst;
import com.atguigu.tingshu.common.rabbit.service.RabbitService;
import com.atguigu.tingshu.common.util.AuthContextHolder;
import com.atguigu.tingshu.common.util.MongoUtil;
import com.atguigu.tingshu.model.user.UserListenProcess;
import com.atguigu.tingshu.user.service.UserListenProcessService;
import com.atguigu.tingshu.vo.album.TrackStatMqVo;
import com.atguigu.tingshu.vo.album.TrackStatVo;
import com.atguigu.tingshu.vo.user.UserListenProcessVo;
import com.atguigu.tingshu.vo.user.UserListenProcessVo;
import org.joda.time.DateTime;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Sort;
import org.springframework.data.mongodb.core.MongoTemplate;
import org.springframework.data.mongodb.core.query.Criteria;
import org.springframework.data.mongodb.core.query.Query;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;

import javax.sound.midi.Track;
import java.math.BigDecimal;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
import java.util.UUID;
import java.util.concurrent.TimeUnit;

@Service
@SuppressWarnings({"unchecked", "rawtypes"})
public class UserListenProcessServiceImpl implements UserListenProcessService {

	@Autowired
	private MongoTemplate mongoTemplate;

    @Autowired
    private RabbitService rabbitService;


    @Autowired
    private StringRedisTemplate redisTemplate;


    /**
     * 查询用户播放声音的暂停时间
     * @param trackId
     * @return
     */
    @Override
    public BigDecimal getTrackBreakSecond(Long trackId) {
        Long userId = AuthContextHolder.getUserId();
        //1.从MongoDB中查询
        //1.1构建一个条件对象
        Criteria criteria = Criteria.where("userId").is(userId).and("trackId").is(trackId);
        //1.2构建一个查询对象
        Query query = new Query(criteria);
        //1.3定义一个表名字
        // 用户id作为分表的规则:userId:1--user_1  ,userId:2--user_2  ,userId:100--user 100 ,userId:101:user_1
        //userId%100余数
        String collectionName = MongoUtil.getCollectionName(MongoUtil.MongoCollectionEnum.USER_LISTEN_PROCESS, userId);
        UserListenProcess userListenProcess = mongoTemplate.findOne(query, UserListenProcess.class, collectionName);
        if (userListenProcess == null){
            return new BigDecimal("0");
        }
        return userListenProcess.getBreakSecond();
    }

    /**
     * 更新用户播放进度
     * @param userListenProcessVo
     */
    @Override
    public void updateListenProcess(UserListenProcessVo userListenProcessVo) {
        Long userId = AuthContextHolder.getUserId();
        Long trackId = userListenProcessVo.getTrackId();
        //0.先查询有没有记录
        //0.1创建一个条件对象
        Criteria criteria = Criteria.where("userId").is(userId).and("trackId").is(trackId);
        //0.2创建一个查询对象
        Query query = new Query(criteria);
        //集合名字
        String collectionName = MongoUtil.getCollectionName(MongoUtil.MongoCollectionEnum.USER_LISTEN_PROCESS, userId);
        UserListenProcess userListenProcess = mongoTemplate.findOne(query, UserListenProcess.class, collectionName);
        //1.没有记录要保存(初始化)
        if (userListenProcess == null){
            userListenProcess = new UserListenProcess();
            userListenProcess.setId(userId+"_"+trackId);
            userListenProcess.setUserId(userId);
            userListenProcess.setTrackId(trackId);
            userListenProcess.setBreakSecond(userListenProcessVo.getBreakSecond());
            userListenProcess.setIsShow(1);
            userListenProcess.setCreateTime(new Date());
            userListenProcess.setUpdateTime(new Date());
            mongoTemplate.save(userListenProcess,collectionName);
        }else {
            //2.有记录要更新
            userListenProcess.setBreakSecond(userListenProcessVo.getBreakSecond());
            userListenProcess.setUpdateTime(new Date());
            mongoTemplate.save(userListenProcess,collectionName); //在MongoDB中save方法会自动判断是更新还是插入
        }

        //记录播放量(专辑的播放量,声音的播放量)
        //对于同一个用户当天不管播放这个声音多少次, 这个声音的播放量只加一次
        //涉及到的元素 userID day redis

        //使用分布式锁(一步到位的解决方法)
        //zk mysql redis redisson....都可以来做分布式锁
        //Reids的API:sentx可以实现分布式锁的功能, 在java中对于的是setIfAbsent方法
        //Redis的另一种解决方案bitmp 位数组
        //2种解决策略的维度
        //维度一:上游只发送一次,下游也就只处理一次(在上游限制)
        //维度二:上游发送多次,下游处理多次(在下游限制)


        String bitMapKey ="user:track:" + new DateTime().toString("yyyyMMdd")+":"+userListenProcessVo.getTrackId();
        Boolean aBoolean = redisTemplate.opsForValue().setBit(bitMapKey, userId, true);
        if (!aBoolean){
            //从Redis中删除这个位数组
            redisTemplate.expire(bitMapKey, 1, TimeUnit.DAYS);
            TrackStatMqVo trackStatMqVo= prepareMgDto(userListenProcessVo);
            rabbitService.sendMessage(MqConst.EXCHANGE_TRACK, MqConst.ROUTING_TRACK_STAT_UPDATE, JSONObject.toJSONString(trackStatMqVo));

        }
    }

    @Override
    public Map<String, Object> getLatelyTrack() {
        HashMap<String, Object> map = new HashMap<>();
        Long userId = AuthContextHolder.getUserId();
        //0.先查询有没有记录
        //0.1创建一个条件对象
        Criteria criteria = Criteria.where("userId").is(userId);
        //设置一个排序
        Sort sort = Sort.by(Sort.Direction.DESC,"createTime");
        //0.2创建一个查询对象
        Query query = new Query(criteria);
        query.with(sort);
        String collectionName = MongoUtil.getCollectionName(MongoUtil.MongoCollectionEnum.USER_LISTEN_PROCESS, userId);
        UserListenProcess userListenProcess = mongoTemplate.findOne(query, UserListenProcess.class, collectionName);
        if (userListenProcess==null){
            return null;
        }
        map.put("albumId",userListenProcess.getAlbumId());
        map.put("trackId",userListenProcess.getTrackId());

        return map;
    }


    /**
     * 封装数据
     * @param userListenProcessVo
     * @return
     */
    private TrackStatMqVo prepareMgDto(UserListenProcessVo userListenProcessVo) {
        TrackStatMqVo trackStatMqVo = new TrackStatMqVo();
        trackStatMqVo.setBusinessNo(UUID.randomUUID().toString());
        trackStatMqVo.setAlbumId(userListenProcessVo.getAlbumId());
        trackStatMqVo.setTrackId(userListenProcessVo.getTrackId());
        trackStatMqVo.setStatType("0701");
        trackStatMqVo.setCount(1);


        return trackStatMqVo;
    }
}
